SQL注入、占位符拼接符
一、什么是SQL注入
官方:
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
个人:
用户在网页输入框中输入SQL命令后,后台接收没后没有进行识别或类型转换,而把它直接运行了。直接运行的话它可是可以直接操作数据库的SQL命令,而不是后台期望的给SQL命令的普通参数。
记一次SQL注入实战 http://blog.jobbole.com/105586/
二、Mybatis中的占位符和拼接符
1、占位符
(1)#{}表示一个占位符号,通过#{}把parameterType 传入的内容通过preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。
(2)#{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
例如(这是用JDBC编写,在Mybatis中我们看不到PreparedStatement,只要是用占位符#{},它自动实现这过程):
String sql = “insert into user (name,pwd) values(?,?)”;
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, “jack”); //占位符顺序从1开始
ps.setString(2, “123456”); //也可以使用setObject
ps.executeQuery();
2、拼接符
${}表示拼接sql串,通过${}可以将parameterType 传入的内容直接拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
三、为什么PreparedStatement 有效的防止sql注入?
1、PreparedStatement简介
PreparedStatement是用来执行SQL查询语句的API之一,Java提供了 Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。
2、普通SQL注入简介
比如:某个网站的登录验证SQL查询代码为:
strSQL =
"SELECT * FROM users WHERE name = '"
+ userName +
"' and pw = '"+ passWord +"';"
恶意填入:
userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";
那么最终SQL语句变成了:
strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"
因为WHERE条件恒为真,这就相当于执行:
strSQL = "SELECT * FROM users;"
因此可以达到无账号密码亦可登录网站。
3、使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入
在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据库所运行。
即SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'、数据库也会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令。
补充1:在页面输入的时候可以加入校验,不可输入sql关键字,不可输入空格,也可以防止SQL注入。
补充2:PreparedStatement比 Statement 更快
使用 PreparedStatement 最重要的一点好处是它拥有更佳的性能优势,SQL语句会预编译在数据库系统中。执行计划同样会被缓存起来,它允许数据库做参数化查询。使用预处理语句比普通的查询更快,因为它做的工作更少(数据库对SQL语句的分析,编译,优化已经在第一次查询前完成了)。为了减少数据库的负载,生产环境中德JDBC代码你应该总是使用PreparedStatement 。值得注意的一点是:为了获得性能上的优势,应该使用参数化sql查询而不是字符串追加的方式。下面两个SELECT 查询,第一个SELECT查询就没有任何性能优势。
SQL Query 1:字符串追加形式的PreparedStatement
String loanType = getLoanType();
PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=" + loanType);
SQL Query 2:使用参数化查询的PreparedStatement
PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=?");
prestmt.setString(1,loanType);
很明显Mybatis中是用的参数化查询
参考:http://www.importnew.com/5006.html